﻿using System;
using System.Data;
using System.Data.Common;

namespace DBA.Data.ADO
{
    /// <summary>
    /// 采用了partial关键字，目前将DataAccessLibrary分成两个部分
    /// 数据访问函数库的基类
    /// 
    /// </summary>
    public partial class DataAccessLibrary
    {
        #region 内部成员。_ 下划线开始的是类的内部成员，小写字母开头的是函数内部成员
        /// <summary>
        /// 当不使用web.config里面设置的连接字符串的时候使用
        /// </summary>
        private string _ConnectionString = string.Empty;

        /// <summary>
        /// 连接数据库的连接方式
        /// </summary>
        private string _ProviderName = "";

        /// <summary>
        /// 如果不使用Webconfig里面的数据库驱动的话，需要使用这个。
        /// </summary>
        private DbProviderFactory _DbProvider;

        /// <summary>
        /// 出现异常时，记录出错信息，包括访问的网页、SQL语句、错误原因、访问时间等
        /// 对于外部（调用者）来说是只读的，而对于内部或者子类来说是可以写入的，所以protected
        /// </summary>
        protected string _ErrorMessage;

        /// <summary>
        /// 获取执行SQL查询语句后影响的行数
        /// 对于外部（调用者）来说是只读的，而对于内部或者子类来说是可以写入的，所以protected
        /// </summary>
        protected int _ExecuteRowCount;


        /// <summary>
        /// 一个DbCommand， 函数库的核心
        /// </summary>
        public DbCommand Command;



        #endregion

        #region 属性
        #region 设置连接字符串
        /// <summary>
        /// 获取或者修改连接字符串
        /// </summary>
        public string ConnectionString
        {
            set { _ConnectionString = value; }
            get
            {
                if (_ConnectionString == string.Empty)      //如果没有设置连接字符串,那么使用默认的连接字符串
                    _ConnectionString = CommonFactory.ConnectionString;

                return _ConnectionString;
            }
        }
        #endregion

        #region 设置连接数据库的驱动名称
        /// <summary>
        /// 读取或者设置连接数据库的驱动名称
        /// </summary>
        public string ProviderName
        {
            set
            {
                //设置了连接数据库的驱动名称，表示不使用Webconfig里面的默认设置，所以要根据这个单独设立一个“工厂”
                _ProviderName = value;
                _DbProvider = DbProviderFactories.GetFactory(value);
            }
            get
            {
                if (_ProviderName == "")
                    //没有设置单独的名称，使用默认的名称
                    _ProviderName = CommonFactory.ProviderName;

                return _ProviderName;
            }
        }
        #endregion

        #region DbProvider。
        /// <summary>
        /// 获取DbProvider
        /// </summary>
        public DbProviderFactory DatabaseProvider
        {
            get { return _DbProvider; }
        }
        #endregion

        #region ErrorMessage。记录出错信息
        /// <summary>
        /// 获取出错信息，没有错误的话返回string.Empty 
        /// </summary>
        public string ErrorMessage
        {
            get { return _ErrorMessage; }
        }
        #endregion

        #region ExecuteRowCount。记录执行sql影响的行数
        /// <summary>
        /// 获取执行SQL语句影响的行数
        /// </summary>
        public int ExecuteRowCount
        {
            get { return _ExecuteRowCount; }
        }
        #endregion

        #region IsUseTrans。标记是否已经启用了ado.net 事务
        /// <summary>
        /// 标记是否已经启用了ado.net 事务
        /// </summary>
        public bool IsUseTrans
        {
            set { _IsUseTrans = value; }
            get { return _IsUseTrans; }
        }
        #endregion

        //加载辅助管理的实例

        #region 加载存储过程参数的管理部分
        /// <summary>
        /// 标记是否已经启用了ado.net 事务
        /// </summary>
        private bool _IsUseTrans;
        /// <summary>
        /// 处理事务的管理部分
        /// </summary>
        private ManagerTran _ManagerTran;
        /// <summary>
        /// 加载事务机制
        /// </summary>
        public ManagerTran ManagerTran
        {
            get
            {
                if (_ManagerTran == null)
                {
                    _ManagerTran = new ManagerTran(this);
                }
                return _ManagerTran;
            }
            set
            {
                _ManagerTran = value;
            }
        }
        #endregion

        #region 加载存储过程的管理部分
        /// <summary>
        /// 处理存储过程参数的管理部分
        /// </summary>
        private ManagerParameter _ManagerParameter;
        /// <summary>
        /// 加载处理存储过程参数的实例。用这个实例来添加存储过程的参数
        /// </summary>
        public ManagerParameter ManagerParameter
        {
            get
            {
                if (_ManagerParameter == null)
                {
                    _ManagerParameter = new ManagerParameter(this);
                }
                return _ManagerParameter;
            }
            set
            {
                _ManagerParameter = value;
            }
        }
        #endregion

        #region 加载不同数据库扩张sql语句部分的管理部分
        /// <summary>
        /// 加载添加、修改的管理部分
        /// </summary>
        private ManagerSQL _ModifyData;
        /// <summary>
        /// 根据ProviderName类型加载不同的ManagerSQL子类，如sqlclient,oleDbmanagesql的子类
        /// </summary>
        public ManagerSQL ModifyData
        {
            get
            {
                if (_ModifyData == null)
                {
                    switch (this.ProviderName) 
                    {
                        case "System.Data.SqlClient":     //SqlClient "System.Data.SqlClient"
                            _ModifyData = new SqlClientManageSql(this);
                            break;

                        default:     //OleDb
                            _ModifyData = new OleDbManageSql(this);
                            break;

                        case "System.Data.Odbc":     //Odbc
                            _ModifyData = new OdbcManageSql(this);
                            break;

                        case "System.Data.OracleClient":
                            _ModifyData = new OracleClientManageSql(this);
                            break;
                    }                    
                }
                return _ModifyData;
            }
            set
            {
                _ModifyData = value;
            }
        }
        #endregion

        #endregion

        //===============================

        #region 无参初始化
        /// <summary>
        /// 初始化。使用默认的数据库类型
        /// </summary>
        public DataAccessLibrary()
        {
            //在创建实例的时候会自动设置默认的连接字符串
            //信息来至web.config文件
            this._DbProvider = CommonFactory.DbProvider;   //使用默认的工厂
            Command = CommonFactory.CreateCommand(this.ConnectionString, this._DbProvider);
        }

        public DataAccessLibrary(DBA.Data.Hibernate.NHibernateQuery nhQuery)
        {
            //在创建实例的时候会自动设置默认的连接字符串
            //信息来至web.config文件
            this._DbProvider = CommonFactory.DbProvider;   //使用默认的工厂
            //Command = CommonFactory.CreateCommand(this.ConnectionString, this._DbProvider);
            Command = (DbCommand)nhQuery.CurrentSession.Connection.CreateCommand();
            Command.Connection = (DbConnection)nhQuery.CurrentSession.Connection;

            //transaction.Enlist(command);
        }
        #endregion

        #region 有参初始化
        /// <summary>
        /// 不使用默认的数据库类型的时候使用
        /// </summary>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="providerName">数据库驱动的名称。System.Data.SqlClient、System.Data.OleDb 、System.Data.Odbc、System.Data.OracleClient等</param>
        public DataAccessLibrary(string connectionString, string providerName)
        {
            //修改数据库类型，然后才能创建实例
            this.ConnectionString = connectionString;
            this.ProviderName = providerName;

            Command = CommonFactory.CreateCommand(this.ConnectionString, this._DbProvider);
        }
        #endregion

        #region 释放资源Dispose
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            if (_ManagerTran != null)
                _ManagerTran = null;
            if (_ManagerParameter != null)
                _ManagerParameter = null;

            this._ErrorMessage = null;
            Command.Parameters.Clear();
            Command.Connection.Close();
            Command.Dispose();

        }
        #endregion

        #region 会重复使用的函数

        #region 设置Command的CommandText和CommandType
        /// <summary>
        /// 设置Command的CommandText和CommandType
        /// </summary>
        /// <param name="commandText"></param>
        public void SetCommand(string commandText)
        {
            this._ErrorMessage = string.Empty;      //清空出错信息
            this._ExecuteRowCount = 0;              //重置影响的行数

            //这种处理方式不太理想，但是目前还没有找到更好的方式
            string state = commandText.Substring(0, 3).ToLower();

            switch (state)
            {
                case "pro":
                case "sp_":
                case "dt_":
                case "ms_":
                case "xp_":
                    Command.CommandType = CommandType.StoredProcedure;
                    break;

                default:
                    Command.CommandType = CommandType.Text;
                    break;
            }

            Command.CommandText = commandText;
        }

        public void SetStoredCommand(string commandText)
        {
            this._ErrorMessage = string.Empty;      //清空出错信息
            this._ExecuteRowCount = 0;              //重置影响的行数
            Command.CommandType = CommandType.StoredProcedure;
            Command.CommandText = commandText;
        }
        /// <summary>
        /// 在使用DataReader或者开始事务的时候，需要手动打开连接。
        /// 注意：DataReader使用完毕之后必须手动关闭连接。
        /// </summary>
        public void ConnectionOpen()
        {
            if (Command.Connection.State == ConnectionState.Broken || Command.Connection.State == ConnectionState.Closed)
                Command.Connection.Open();
        }
        #endregion

        #region 保存出错信息
        //设置出错信息
        /// <summary>
        /// 当发生异常时，所作的处理
        /// </summary>
        /// <param name="functionName">函数名称</param>
        /// <param name="commandText">查询语句或者存储过程</param>
        /// <param name="message">错误信息</param>
        public void SetErrorMessage(string functionName, string commandText, string message)
        {
            //设置返回给调用者的错误信息
            this._ErrorMessage = functionName + "函数出现异常。\r\n错误信息：" + message
                + "\r\n查询语句：" + commandText;

            if (IsUseTrans)
            {
                _ManagerTran.TranRollBack();			    //事务模式下：自动回滚事务，不用调用者回滚
            }
            this.Command.Connection.Close();		//关闭连接
            AddLogError(this._ErrorMessage);	    //记录到错误日志
        }

        #endregion

        #region 记录错误日志
        /// <summary>
        /// 如果要使用的话，根据你的需要进行修改。
        /// </summary>
        /// <param name="errorDescribe">描述信息，即保存到日志文件里的信息</param>
        public static void AddLogError(string errorDescribe)
        {
            string path = System.Web.HttpContext.Current.Server.MapPath("~/log/");

            //判断是否建立了log文件夹
            if (!System.IO.Directory.Exists(path))
                System.IO.Directory.CreateDirectory(path);

            //记录到错误日志
            string FilePath = path + "/" + DateTime.Now.ToString("yyyyMMdd") + ".txt";
            System.Text.StringBuilder str = new System.Text.StringBuilder();

            str.Append(DateTime.Now.ToString());    //访问的时间
            str.Append("\t");
            str.Append(System.Web.HttpContext.Current.Request.Url.PathAndQuery); //访问的网页和URL参数
            str.Append("\r\n");
            str.Append(errorDescribe);              //填写正文
            str.Append("\r\n\r\n");

            System.IO.StreamWriter sw = null;
            try
            {
                sw = new System.IO.StreamWriter(FilePath, true, System.Text.Encoding.Unicode);
                sw.Write(str.ToString());
            }
            catch (Exception ex)
            {
                System.Web.HttpContext.Current.Response.Write("没有访问日志文件的权限！或日志文件只读!" + ex.Message);
            }
            finally
            {
                if (sw != null)
                    sw.Close();
            }
        }
        #endregion

        #endregion

    }
}
